package result

import (
	"fmt"
	"net/http"

	"github.com/go-playground/validator/v10"
	"github.com/labstack/echo/v4"
)

const (
	OK                    = 200
	BAD_REQUEST           = 400
	REQUIRED_ACCOUNT      = 1000
	REQUIRED_PRIVATE      = 1001
	REQUIRED_AMOUNT       = 1002
	REQUIRED_CONTRACT     = 1003
	REQUIRED_FROM_ACCOUNT = 1004
	REQUIRED_TO_ACCOUNT   = 1005
	IS_CONTRACT_ADDRESS   = 1006
	NOT_CONTRACT_ADDRESS  = 1007
	SAME_ACCOUNT          = 1008
	CRYPTO_CURRENCY_ERROR = 1009
	ERROR                 = 9999
)

var Message = map[int]string{
	OK:                    "OK",
	BAD_REQUEST:           "请求错误",
	REQUIRED_ACCOUNT:      "账号必填",
	REQUIRED_PRIVATE:      "私钥必填",
	REQUIRED_AMOUNT:       "金额必填",
	REQUIRED_CONTRACT:     "合约地址必填",
	REQUIRED_FROM_ACCOUNT: "转出账号必填",
	REQUIRED_TO_ACCOUNT:   "转入账号必填",
	IS_CONTRACT_ADDRESS:   "这是合约地址",
	NOT_CONTRACT_ADDRESS:  "这不是合约地址",
	SAME_ACCOUNT:          "发起方与收款方不能是同一个账户",
	CRYPTO_CURRENCY_ERROR: "加密货币类型错误",
	ERROR:                 "ERROR",
}

type AppError struct {
	Code    int
	Message string
}

func NewAppError(code int, message string) *AppError {
	return &AppError{
		Code:    code,
		Message: message,
	}
}

func (e *AppError) Error() string {
	return fmt.Sprintf("%d:%s", e.Code, e.Message)
}

func AppErrorHandler(err error, c echo.Context) {
	var (
		code = http.StatusInternalServerError
		msg  string
	)
	if he, ok := err.(*AppError); ok {
		code = he.Code
		msg = he.Message
	} else if ee, ok := err.(*echo.HTTPError); ok {
		code = ee.Code
		msg = http.StatusText(code)
	} else {
		msg = http.StatusText(code)
	}

	if !c.Response().Committed {
		if c.Request().Method == echo.HEAD {
			err := c.NoContent(code)
			if err != nil {
				c.Logger().Error(err)
			}
		} else {
			err := c.JSON(code, NewAppError(code, msg))
			if err != nil {
				c.Logger().Error(err)
			}
		}
	}
}

type Result struct {
	Code          int         `json:"code,omitempty" validate:"required"`
	Message       string      `json:"message,omitempty" validate:"required"`
	DetailMessage string      `json:"detailMessage,omitempty"`
	Data          interface{} `json:"data,omitempty"`
}

func Ok(data interface{}) *Result {
	code := OK
	return &Result{
		Code:    code,
		Message: Message[code],
		Data:    data,
	}
}

type AppVolidator struct {
	Validator *validator.Validate
}

func (v *AppVolidator) Validate(i interface{}) error {
	if err := v.Validator.Struct(i); err != nil {
		// Optionally, you could return the error to give each route more control over the status code
		return echo.NewHTTPError(http.StatusBadRequest, err.Error())
	}
	return nil
}
